package com.csii.activiti.server.core.smart.process;

import cn.hutool.core.collection.CollUtil;
import com.csii.activiti.server.core.constant.ApprovalConfigConstant;
import com.csii.activiti.server.core.constant.CommonConstant;
import com.csii.activiti.server.core.constant.FlowNodeTypeConstant;
import com.csii.activiti.server.core.entity.*;
import com.csii.activiti.server.core.utils.ConversionELExperssionUtils;
import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ConvertFlowToBpmn {
    //开始节点ID
    private static final String START = "start";
    //结束节点ID
    private static final String END = "end";

    private static final String COUNTERSIGN_FLOW_EXPRESSION = "${"+ ApprovalConfigConstant.COUNTERSIGN_FLOW_VARIABLE_KEY+"}";

    private ActFlowConfiguration flow;

    public ConvertFlowToBpmn(ActFlowConfiguration flow){
        this.flow = flow;
    }

    public String getBpmnXmlString(){
        String bpmnString = new String(getBpmnXmlByte());
        //bytes = bytes.repyiqian laceAll("&lt;", "<").replaceAll("&gt;", ">");
        return bpmnString;
    }

    public byte[] getBpmnXmlByte(){
        return new BpmnXMLConverter().convertToXML(getBpmnModel());
    }

    public BpmnModel getBpmnModel(){
        //创建bpmn模型
        BpmnModel model = new BpmnModel();
        Process process = new Process();
        model.addProcess(process);
        process.setId(flow.getFlowKey());
        process.setName(flow.getFlowName());
        //创建开始节点
        process.addFlowElement(createStartEvent());
        //创建其他节点
        //单条件
        if (flow.getNodes() != null) {
            List<ActFlowNode> nodes = flow.getNodes();
            List<String> finallyNodeIds = processFlowNodeList(nodes, process, CollUtil.toList(START));
            //创建结束节点
            process.addFlowElement(createEndEvent());
            for (String finallyNodeId : finallyNodeIds) {
                process.addFlowElement(createSequenceFlow(finallyNodeId, END));
            }
        }else if(flow.getMultiNodes() != null){
            //多条件
            List<ActFlowMultiNode> multiNodes = flow.getMultiNodes();
            //创建结束节点
            process.addFlowElement(createEndEvent());
            for (ActFlowMultiNode multiNode : multiNodes) {
                List<ActFlowNode> nodes = multiNode.getNodes();
                List<String> finallyNodeIds = processFlowNodeList(nodes, process, null);
                process.addFlowElement(createSequenceFlow(START, nodes.get(0).getId(), ConversionELExperssionUtils.conversionFlowConditionGroupToEL(multiNode.employConditionGroups())));
                for (String finallyNodeId : finallyNodeIds) {
                    process.addFlowElement(createSequenceFlow(finallyNodeId, END));
                }

            }
        }else{
            //创建结束节点
            process.addFlowElement(createEndEvent());
            //创建链接线
            process.addFlowElement(createSequenceFlow(START, END));
        }

        // 2.生成BPMN自动布局
        new BpmnAutoLayout(model).execute();
        return model;
    }

    private List<String> processFlowNodeList(List<ActFlowNode> nodes,Process process,List<String> lastNodeIds){
        List<String> currentLastNodeIds = new ArrayList<>();
        if (CollUtil.isNotEmpty(lastNodeIds)){
            currentLastNodeIds.addAll(lastNodeIds);
        }
        for (ActFlowNode node : nodes) {
            if(FlowNodeTypeConstant.LINK_NODE.equals(node.getNodeType())){
                //创建排他网关
                process.addFlowElement(createExclusiveGateway(node.getId(), node.getNodeName()));
                //连线
                for (String currentLastNodeId : currentLastNodeIds) {
                    process.addFlowElement(createSequenceFlow(currentLastNodeId, node.getId()));
                }
                currentLastNodeIds.clear();
                List<ActFlowMultiNode> nodeLink = node.getNodeLink();
                List<String> finallyNodeIds = new ArrayList<>();
                for (ActFlowMultiNode actFlowMultiNode : nodeLink) {
                    finallyNodeIds.addAll(processFlowNodeList(actFlowMultiNode.getNodes(), process, null));
                    process.addFlowElement(createSequenceFlow(node.getId(), actFlowMultiNode.getNodes().get(0).getId(), ConversionELExperssionUtils.conversionFlowConditionGroupToEL(actFlowMultiNode.employConditionGroups())));
                }
                currentLastNodeIds.addAll(finallyNodeIds);
            }else{
                if (FlowNodeTypeConstant.PEOPLE_WHO_COPIED.equals(node.getNodeType())){
                    //抄送人
                    process.addFlowElement(createServiceTask(node.getId(), node.getNodeName(), "${peopleWhoCopiedDelegate}"));
                }else if(FlowNodeTypeConstant.SERVICE_NODE.equals(node.getNodeType())){
                    //服务节点
                    process.addFlowElement(createServiceTask(node.getId(), node.getNodeName(), node.getServiceNodeConfiguration().getServiceExpression()));
                }
                else{
                    //设置会签或者或签
                    UserTask manyUserTask = createManyUserTask(node.getId(), node.getNodeName(), "${countersignApprover}", ApprovalConfigConstant.COUNTERSIGN.equals(node.getConfigurationItem().getApprovalMechanism()));
                    process.addFlowElement(manyUserTask);
                    //设置流程催办
                    if (node.getConfigurationItem() != null){
                        if (node.getConfigurationItem().getFlowUrgingConfiguration() != null) {
                            ActFlowUrgingConfiguration flowUrgingConfiguration = node.getConfigurationItem().getFlowUrgingConfiguration();
                            boundaryEvent(process, flowUrgingConfiguration.getId(),flowUrgingConfiguration.getDelayHour(), manyUserTask,CommonConstant.URGING_SERVICE_NODE_ID,CommonConstant.URGING_SERVICE_NODE_NAME,CommonConstant.URGING_SERVICE_NODE_EXPRESSION);
                        }
                        if (node.getConfigurationItem().getFlowAutoApprovalConfiguration() != null){
                            ActFlowAutoApprovalConfiguration flowAutoApprovalConfiguration = node.getConfigurationItem().getFlowAutoApprovalConfiguration();
                            boundaryEvent(process, flowAutoApprovalConfiguration.getId(),flowAutoApprovalConfiguration.getDelayHour(), manyUserTask,CommonConstant.AUTO_APPROVAL_SERVICE_NODE_ID,CommonConstant.AUTO_APPROVAL_SERVICE_NODE_NAME,CommonConstant.AUTO_APPROVAL_SERVICE_NODE_EXPRESSION);
                        }
                    }

                }
                if (!currentLastNodeIds.isEmpty()){
                    //连线
                    for (String lastNodeId : currentLastNodeIds) {
                        process.addFlowElement(createSequenceFlow(lastNodeId, node.getId()));
                    }
                    currentLastNodeIds.clear();
                }
                currentLastNodeIds.add(node.getId());
            }
        }
        return currentLastNodeIds;
    }

    private void boundaryEvent(Process process, String boundaryNodeId,int delayHour, UserTask manyUserTask,String serviceNodeId,String serviceNodeName,String serviceNodeExpression) {

        //创建延期操作
        BoundaryEvent boundaryEvent = new BoundaryEvent();
        boundaryEvent.setCancelActivity(false);
        boundaryEvent.setAttachedToRef(manyUserTask);
        boundaryEvent.setId(boundaryNodeId);
        TimerEventDefinition timerEventDefinition = new TimerEventDefinition();
        timerEventDefinition.setTimeDuration("PT"+delayHour+"H");
        boundaryEvent.setEventDefinitions(CollUtil.newArrayList(timerEventDefinition));
        process.addFlowElement(boundaryEvent);

        //创建服务节点(没有才创建)
        if (!process.containsFlowElementId(serviceNodeId)){
            ServiceTask serviceTask = createServiceTask(serviceNodeId, serviceNodeName, serviceNodeExpression);
            process.addFlowElement(serviceTask);
        }
        //连线
        process.addFlowElement(createSequenceFlow(boundaryEvent.getId(), serviceNodeId, null));
    }


    //创建会签task
    private UserTask createManyUserTask(String id, String name, String assignee,boolean isCountersign){
        UserTask userTask = createUserTask(id, name, assignee);
        MultiInstanceLoopCharacteristics multi = new MultiInstanceLoopCharacteristics();
        multi.setSequential(false);
        multi.setElementVariable("countersignApprover");
        multi.setInputDataItem(COUNTERSIGN_FLOW_EXPRESSION);
        if (!isCountersign){
            multi.setCompletionCondition("${nrOfCompletedInstances == 1}");
        }
        userTask.setLoopCharacteristics(multi);
        ExtensionElement extensionElement = new ExtensionElement();
        extensionElement.setName("initiator-can-complete");
        extensionElement.setNamespacePrefix("modeler");
        extensionElement.setNamespace("http://activiti.com/modeler");
        extensionElement.setElementText("false");
        Map<String, List<ExtensionElement>> mapAndList = new HashMap<>();
        mapAndList.put("initiator-can-complete", CollUtil.newArrayList(extensionElement));
        userTask.setExtensionElements(mapAndList);
        return userTask;
    }

    //创建task
    private UserTask createUserTask(String id, String name, String assignee) {
        UserTask userTask = new UserTask();
        userTask.setName(name);
        userTask.setId(id);
        userTask.setAssignee(assignee);
        return userTask;
    }

    //创建服务task
    private ServiceTask createServiceTask(String id, String name, String elExpression) {
        ServiceTask serviceTask = new ServiceTask();
        serviceTask.setId(id);
        serviceTask.setName(name);
        serviceTask.setImplementation(elExpression);
        serviceTask.setImplementationType("delegateExpression");
        return serviceTask;
    }

    //创建排他网关
    private ExclusiveGateway createExclusiveGateway(String id, String name) {
        ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
        exclusiveGateway.setId(id);
        exclusiveGateway.setName(name);
        return exclusiveGateway;
    }

    //创建箭头
    private SequenceFlow createSequenceFlow(String from, String to) {
        return createSequenceFlow(from,to,null);
    }

    //创建箭头带条件
    private SequenceFlow createSequenceFlow(String from, String to,String conditionExpression) {
        SequenceFlow flow = new SequenceFlow();
        flow.setSourceRef(from);
        flow.setTargetRef(to);
        flow.setConditionExpression(conditionExpression);
        return flow;
    }


    private StartEvent createStartEvent() {
        StartEvent startEvent = new StartEvent();
        startEvent.setId(START);
        return startEvent;
    }


    private EndEvent createEndEvent() {
        EndEvent endEvent = new EndEvent();
        endEvent.setId(END);
        return endEvent;
    }
}
